package com.conan.app.dailyflickr.activity;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import android.app.Service;
import android.appwidget.AppWidgetManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.graphics.Bitmap;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.text.TextUtils;
import android.util.Log;
import android.widget.RemoteViews;

import com.conan.app.flickrdaily.R;
import com.conan.app.dailyflickr.App;
import com.conan.app.dailyflickr.AppData;
import com.conan.app.dailyflickr.AppData.COMMAND_ACTION;
import com.conan.app.dailyflickr.app.ApplicationUtils;
import com.conan.app.dailyflickr.app.BitmapHttpGet;
import com.conan.app.dailyflickr.app.DailyPhotoData;
import com.conan.app.dailyflickr.app.DailyPhotoData.Photo;
import com.conan.app.dailyflickr.app.DailyPhotoData.PhotoList;
import com.conan.app.dailyflickr.app.DailyPhotoData.PhotoSize;
import com.conan.app.dailyflickr.app.ImageDownloadTask.ImageDownloadListener;
import com.conan.app.dailyflickr.provider.ProviderUtils;
import com.conan.app.dailyflickr.provider.ProviderUtils.DailyInfo;
import com.conan.app.dailyflickr.provider.ProviderUtils.LayoutType;


/**
 * Background service to build any requested widget updates. Uses a single
 * background thread to walk through an update queue, querying
 * {@link WebserviceHelper} as needed to fill database. Also handles scheduling
 * of future updates, usually in 6-hour increments.
 */

public class UpdateService extends Service implements ImageDownloadListener{
    public static final String ACTION_UPDATE_ALL = "com.handroid.dailyflickr.UPDATE_ALL";

    final PhotoSize LARGE_SIZE = PhotoSize.SMALL;
    final PhotoSize SIZE = PhotoSize.SMALL_SQUARE;

    private HashMap<Integer, PhotoList> mPhotosCache = new HashMap<Integer, DailyPhotoData.PhotoList>();


    private BitmapHttpGet mBmManager = new BitmapHttpGet(UpdateService.this, this);

    public boolean mProcessingFlag = false;
    public boolean mLoadingFlag = false;
    private int[] imgViewArray ={
            R.id.img_0, R.id.img_1, R.id.img_2, R.id.img_3, R.id.img_4,
            R.id.img_5, R.id.img_6, R.id.img_7, R.id.img_8, R.id.img_9,
            R.id.img_10, R.id.img_11, R.id.img_12, R.id.img_13, R.id.img_14
    };

    @Override
    public IBinder onBind(Intent arg0) {
        return null;
    }

    /* (non-Javadoc)
     * @see com.conan.dailyflickr.app.BitmapManager.ImageDownloadListener#completed(boolean, java.lang.String)
     */
    @Override
    public void completed(int widgetId, int position, Bitmap bitmap) {
        updateGetComplete(widgetId, position, bitmap);
    }



    public void updateGetComplete(int widgetId, int position, Bitmap bitmap){
        // if(!mProcessingFlag){
        mProcessingFlag = true;

        RemoteViews updateViews = getRemoteView(this, widgetId);
        AppWidgetManager manager = AppWidgetManager.getInstance(UpdateService.this);

        if (bitmap == null)  return;

        DailyInfo info = DailyFlickrWidget.getWidgetInfo(this, widgetId);
        Photo photo = null;

        if(position < 0){	// update main photo view

            updateViews.setImageViewBitmap(R.id.imv_main_img_of_dailyflickr_id, bitmap);

            updateViews.setTextViewText(R.id.tv_main_message_text_id, info._title);

            updateViews.setOnClickPendingIntent(
                    R.id.imv_main_img_of_dailyflickr_id,
                    DailyFlickrWidget.setPendingIntent(getApplicationContext(), 
                            AppData.COMMAND_ACTION.download_wallpaper, widgetId , -1));

        }else{
            updateViews.setImageViewBitmap(imgViewArray[position], bitmap);
            updateViews.setOnClickPendingIntent(
                    imgViewArray[position],
                    DailyFlickrWidget.setPendingIntent(getApplicationContext(), 
                            AppData.COMMAND_ACTION.refresh_main_view, widgetId , position));

            // update provider
            PhotoList photos = mPhotosCache.get(widgetId);
            if(photos != null && position < photos.getCount()){
                photo = photos.get(position);

                ProviderUtils.updatePhotoGetComplete(this, widgetId, position, photo);
            }
        }

        String title =  getResources().getString(R.string.loading);

        // complete load all image to panel
        if(mBmManager.getRequests(widgetId) <= 0){
            LayoutType layout = new LayoutType(getApplicationContext(), info._layout);

            updateViews.setTextViewText(R.id.tv_main_message_text_id, info._title);

            title = getResources().getString(R.string.str_status, 
                    layout._PER_PAGE*(info._page - 1), layout._PER_PAGE*info._page);

            // remove to widget's updating to avoid the service die unexpected
            ProviderUtils.deleteWidgetUpdating(getApplicationContext(), widgetId);
            // update control buttons
            DailyFlickrWidget.setControlEvent(getApplicationContext(), updateViews, widgetId);
        }

        updateViews.setTextViewText(R.id.tv_flickr_status_refresh ,title);
        manager.updateAppWidget(widgetId, updateViews);

        mProcessingFlag = false;
        //}
    }

    // Main thread for running through any requested widget updates
    // also sets alarm to perform next update.
    public PhotoList handleLoadPage(int widgetId, DailyInfo info) {
        mProcessingFlag = true;
        //  manager = AppWidgetManager.getInstance(this);
        PhotoList photoLst = null;

        if(widgetId != AppWidgetManager.INVALID_APPWIDGET_ID ){			
            // build update

            DailyPhotoData mPhotoDaily = new DailyPhotoData(getBaseContext());
            LayoutType layout = new LayoutType(getApplicationContext(), info._layout);

            // end clear cache
            if(mPhotoDaily.updateDataFromFlickr(info._page, layout._PER_PAGE, info._date.getTime())){
                photoLst = mPhotoDaily.getPhotoList();

                // next day if go over the number pages of days
                // was check in widget provider app
                mBmManager.clearRequestBitmap(widgetId);				

                // update status notify
                RemoteViews updateViews = getRemoteView(this, widgetId);
                AppWidgetManager manager = AppWidgetManager.getInstance(UpdateService.this);
                updateViews.setTextViewText(R.id.tv_main_message_text_id, AppData.STATUS);

                String status = ApplicationUtils.buildDateString(info._date.getTime()) + " @ " + info._page;				
                updateViews.setTextViewText(R.id.tv_main_message_date_id, status);

                manager.updateAppWidget(widgetId, updateViews);

                mPhotosCache.put(widgetId, photoLst);

                // fectch url to dowload image update view
                for(int i = 0; i< photoLst.getCount(); i++){
                    Photo photo = photoLst.get(i);

                    mBmManager.fetchBitmapOnThread(widgetId, info._page,  photo.mID, photo.getUrl(SIZE), i);
                }

                if (TextUtils.isEmpty(info._url)){ 
                    Random ran = new Random();

                    Photo photo = photoLst.get(
                            ran.nextInt(photoLst.getCount()));

                    String urlMainView = photo.getUrl(LARGE_SIZE);
                    mBmManager.fetchBitmapOnThread(widgetId, info._page, photo.mID, urlMainView, -1);

                    info._url = urlMainView;
                    info._title = photo.mTitle;
                }else{
                    // existed main view image
                    mBmManager.fetchBitmapOnThread(widgetId, info._page, info._title, info._url, -1);
                }

                // store provider
                ProviderUtils.updateWidgetInfoToProvider(this, info);

            }else{
                App.makeToastMessage(getResources().getString(R.string.load_failed) + 
                        ApplicationUtils.buildDateString(info._date.getTime()));

                // get old-data from provider to update
                info = ProviderUtils.getWidgetInfoFromProvider(getApplicationContext(), widgetId);

                DailyFlickrWidget.sDailyInfos.put(widgetId, info);
                RemoteViews remoteView = getRemoteView(this, widgetId);
                remoteView.setTextViewText(R.id.tv_flickr_status_refresh, 
                        getResources().getString(R.string.str_status, 
                                layout._PER_PAGE*(info._page - 1),
                                layout._PER_PAGE*info._page));

                AppWidgetManager manager = AppWidgetManager.getInstance(getApplicationContext());
                manager.updateAppWidget(widgetId, remoteView);
            }
        }

        mProcessingFlag = false;
        return photoLst;
    }	

    /**
     * get RemoteView of widget follow widgetId
     *  Aug 16, 2011
     *  @param context
     *  @param widgetId
     *  @return
     */
    private  RemoteViews getRemoteView(Context context, int widgetId){
        DailyInfo info = DailyFlickrWidget.getWidgetInfo(this, widgetId);

        LayoutType layout = new LayoutType(getApplicationContext(), info._layout);
        RemoteViews remoteView =  new RemoteViews(context.getPackageName(), layout._layoutId);

        return remoteView;
    }

    /**
     * 
     *  Aug 16, 2011
     *  @param page
     *  @param id
     */
    public void handleLoadMainView(int widgetId, int id) {
        DailyInfo info = DailyFlickrWidget.getWidgetInfo(this, widgetId);

        Photo photo = null;

        /** check photo is loaded on list image complete	*/
        ArrayList<Photo> _old_list = ProviderUtils.getPhotosFromProvider(this, widgetId);
        if(_old_list != null && id < _old_list.size()){
            photo = _old_list.get(id);
        }else{
            PhotoList photos = mPhotosCache.get(widgetId);
            if(photos == null){
                DailyPhotoData mPhotoDaily = new DailyPhotoData(getBaseContext());
                LayoutType layout = new LayoutType(getApplicationContext(), info._layout);

                if(mPhotoDaily.updateDataFromFlickr(info._page, layout._PER_PAGE, info._date.getTime())){
                    photos = mPhotoDaily.getPhotoList();

                    mPhotosCache.put(widgetId, photos);

                    photo = photos.get(id);
                }
            }
        }

        if(photo == null) return;

        String url = photo.getUrl(LARGE_SIZE);		

        // clear all main view
        if( info!= null && !TextUtils.isEmpty(info._url)){
            mBmManager.clearMainBitmapItem(url);
        }

        ApplicationUtils.deleteFiles(App.getContext(), 
                String.format(AppData.IMAGE_PATTERN, widgetId, -1));

        mBmManager.fetchBitmapOnThread(widgetId, info._page, photo.mID, url, -1);

        /**	update info */
        info._url = url;
        info._title = photo.getTitle();
        ProviderUtils.updateWidgetInfoToProvider(this, info);
    }

    /********************************************************************************************/
    @Override
    public void onCreate() {
        registerConectivityReceivers();
        DailyFlickrWidget.restartWidgetInfo(getApplicationContext());
        super.onCreate();
    }

    /********************************************************************************************/
    private void handleAutoRestartService(){
        int[] appWidgetIds = ProviderUtils.getWidgetUpdating(UpdateService.this);
        if(appWidgetIds != null){
            for(int key: appWidgetIds){
                DailyInfo info = DailyFlickrWidget.getWidgetInfo(UpdateService.this, key);

                handleLoadPage(key, info);
            }
        }
    }

    private Handler mHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case AppData.MSG_AUTO_RESTART:
                handleAutoRestartService();
                break;

            case AppData.MSG_LOAD_PAGE:
                DailyInfo info = DailyFlickrWidget.getWidgetInfo(getApplicationContext(),  msg.arg1);
                ProviderUtils.setWidgetUpdating(getApplicationContext(),  msg.arg1);
                handleLoadPage( msg.arg1, info);
                break;

            case AppData.MSG_MAIN_VIEW:
                handleLoadMainView( msg.arg1,  msg.arg2);
                break;

            default:
                // handleLoadPageWhenConnectivityChange();
                break;
            }
        };
    };
    /**
     * start this service, creating a background processing thread
     * if not already running. If started with {@link UpdateService#ACTION_UPDATE_ALL
     * automatically add all widgets to the requested update queue
     */
    @Override
    public void onStart(Intent intent, int startId) {
        super.onStart(intent, startId);

        if(intent != null && intent.getExtras() != null) {
            /******************** kill service ****************/
            boolean stop = intent.getExtras().getBoolean("stop", false);
            if(stop){
                stopSelf();
                return;
            }

            /*******		update all widget when Internet connection turn on		*******/ 
            boolean connectivity_change = intent.getBooleanExtra(ConnectivityManager.CONNECTIVITY_ACTION, false);
            if(connectivity_change){
                mHandler.sendEmptyMessage(AppData.MSG_CONNECTITVITY_CHANGE);
            }else{			
                /******************** load data ****************/
                int widgetId = intent.getExtras().getInt(AppWidgetManager.EXTRA_APPWIDGET_ID);

                String action = intent.getExtras().getString(AppData.ACTION_NAME);
                if(!TextUtils.isEmpty(action) &&
                        action.contains(COMMAND_ACTION.refresh_main_view.name())) {
                    int id = intent.getExtras().getInt(COMMAND_ACTION.refresh_main_view.name(), -1);
                    Message msg = new Message();
                    msg.arg1 = widgetId;
                    msg.arg2 =  id;
                    msg.what = AppData.MSG_MAIN_VIEW;
                    mHandler.sendMessage(msg);
                }else{
                    Message msg = new Message();
                    msg.arg1 = widgetId;
                    msg.what = AppData.MSG_LOAD_PAGE;
                    mHandler.sendMessage(msg);
                }
            }			
        }else{
            /** service auto-restart service unexpected*/
            mHandler.sendEmptyMessage(AppData.MSG_AUTO_RESTART);
        }
    }


    @Override
    public void onDestroy() {
        unregisterConectivityReceivers();
        mBmManager.stopDownload();		
        super.onDestroy();
    }

    @Override
    public void onLowMemory() {
        super.onLowMemory();
    }

    /*****************************************************************
     *  ConnectivityReceiver class 
     *  register DISconencted wireless connection
     *****************************************************************/
    private ConnectivityReceiver mConnectivityReceiver;

    private void registerConectivityReceivers() {
        if(mConnectivityReceiver == null){	
            mConnectivityReceiver = new ConnectivityReceiver();	
            IntentFilter intentFilter = new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION);
            intentFilter.addAction(Intent.ACTION_CONFIGURATION_CHANGED );
            this.registerReceiver(mConnectivityReceiver, intentFilter);
        }
    }

    private void unregisterConectivityReceivers() {
        if(mConnectivityReceiver != null){
            this.unregisterReceiver(mConnectivityReceiver);
            mConnectivityReceiver = null;
        }

    }	

    private class ConnectivityReceiver extends BroadcastReceiver {  
        @Override
        public void onReceive(final Context context, final Intent intent) {
            // Run the handler in MyExecutor to be protected by wake lock

            String action = intent.getAction();

            /*String extra = "null";
            if(intent.getExtras() != null){
                extra = intent.getExtras().toString(); 
            }*/
            if (TextUtils.equals(action, ConnectivityManager.CONNECTIVITY_ACTION)) {
                Bundle b = intent.getExtras();
                if (b != null) {
                    NetworkInfo netInfo = (NetworkInfo) 
                            b.get(ConnectivityManager.EXTRA_NETWORK_INFO);
                    NetworkInfo.State state = netInfo.getState();

                    if (state == NetworkInfo.State.DISCONNECTED) {
                        mBmManager.changeConnectionInternet(false);
                    }
                }
            }else if(TextUtils.equals(action, Intent.ACTION_CONFIGURATION_CHANGED)){

                AppWidgetManager manager = AppWidgetManager.getInstance(context);
                int[] appWidgetIds = manager.getAppWidgetIds(
                        new ComponentName(context, DailyFlickrWidget.class));

                DailyInfo info = null;
                for(int widgetId : appWidgetIds) {
                    info = DailyFlickrWidget.getWidgetInfo(context, widgetId);
                    if(info != null){
                        RemoteViews remoteView = getRemoteView(context, widgetId);

                        DailyFlickrWidget.setControlEvent(context, remoteView, widgetId);

                        manager.updateAppWidget(widgetId, remoteView);

                        handleLoadPage(widgetId, info);
                    }
                }
            }
        }
    }


    /*****************	Utility functions for test *******************************/
    private void notifyError(String message){
        App.makeToastMessage(message);
    }
}
